// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package help implements the ``go help'' command.

// package help -- go2cs converted at 2022 March 13 06:29:36 UTC
// import "cmd/go/internal/help" ==> using help = go.cmd.go.@internal.help_package
// Original source: C:\Program Files\Go\src\cmd\go\internal\help\help.go
namespace go.cmd.go.@internal;

using bufio = bufio_package;
using bytes = bytes_package;
using fmt = fmt_package;
using io = io_package;
using os = os_package;
using strings = strings_package;
using template = text.template_package;
using unicode = unicode_package;
using utf8 = unicode.utf8_package;

using @base = cmd.go.@internal.@base_package;
using modload = cmd.go.@internal.modload_package;


// Help implements the 'help' command.

public static partial class help_package {

public static void Help(io.Writer w, slice<@string> args) { 
    // 'go help documentation' generates doc.go.
    if (len(args) == 1 && args[0] == "documentation") {
        fmt.Fprintln(w, "// Copyright 2011 The Go Authors. All rights reserved.");
        fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style");
        fmt.Fprintln(w, "// license that can be found in the LICENSE file.");
        fmt.Fprintln(w);
        fmt.Fprintln(w, "// Code generated by mkalldocs.sh; DO NOT EDIT.");
        fmt.Fprintln(w, "// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.");
        fmt.Fprintln(w);
        ptr<object> buf = @new<bytes.Buffer>();
        PrintUsage(buf, _addr_@base.Go);
        ptr<base.Command> usage = addr(new base.Command(Long:buf.String()));
        ptr<base.Command> cmds = new slice<ptr<base.Command>>(new ptr<base.Command>[] { usage });
        {
            var cmd__prev1 = cmd;

            foreach (var (_, __cmd) in @base.Go.Commands) {
                cmd = __cmd; 
                // Avoid duplication of the "get" documentation.
                if (cmd.UsageLine == "module-get" && modload.Enabled()) {
                    continue;
                }
                else if (cmd.UsageLine == "gopath-get" && !modload.Enabled()) {
                    continue;
                }
                cmds = append(cmds, cmd);
                cmds = append(cmds, cmd.Commands);
            }
            cmd = cmd__prev1;
        }

        tmpl(addr(new commentWriter(W:w)), documentationTemplate, cmds);
        fmt.Fprintln(w, "package main");
        return ;
    }
    var cmd = @base.Go;
Args:

    foreach (var (i, arg) in args) {
        foreach (var (_, sub) in cmd.Commands) {
            if (sub.Name() == arg) {
                cmd = sub;
                _continueArgs = true;
                break;
            }
        }        @string helpSuccess = "go help";
        if (i > 0) {
            helpSuccess += " " + strings.Join(args[..(int)i], " ");
        }
        fmt.Fprintf(os.Stderr, "go help %s: unknown help topic. Run '%s'.\n", strings.Join(args, " "), helpSuccess);
        @base.SetExitStatus(2); // failed at 'go help cmd'
        @base.Exit();
    }    if (len(cmd.Commands) > 0) {
        PrintUsage(os.Stdout, _addr_cmd);
    }
    else
 {
        tmpl(os.Stdout, helpTemplate, cmd);
    }
    return ;
}

private static @string usageTemplate = @"{{.Long | trim}}

Usage:

	{{.UsageLine}} <command> [arguments]

The commands are:
{{range .Commands}}{{if or (.Runnable) .Commands}}
	{{.Name | printf ""%-11s""}} {{.Short}}{{end}}{{end}}

Use ""go help{{with .LongName}} {{.}}{{end}} <command>"" for more information about a command.
{{if eq (.UsageLine) ""go""}}
Additional help topics:
{{range .Commands}}{{if and (not .Runnable) (not .Commands)}}
	{{.Name | printf ""%-15s""}} {{.Short}}{{end}}{{end}}

Use ""go help{{with .LongName}} {{.}}{{end}} <topic>"" for more information about that topic.
{{end}}
";

private static @string helpTemplate = "{{if .Runnable}}usage: {{.UsageLine}}\n\n{{end}}{{.Long | trim}}\n";

private static @string documentationTemplate = "{{range .}}{{if .Short}}{{.Short | capitalize}}\n\n{{end}}{{if .Commands}}" + usageTemplate + "{{else}}{{if .Runnable}}Usage:\n\n\t{{.UsageLine}}\n\n{{end}}{{.Long | trim}}\n\n\n{{end}" +
    "}{{end}}";

// commentWriter writes a Go comment to the underlying io.Writer,
// using line comment form (//).
private partial struct commentWriter {
    public io.Writer W;
    public bool wroteSlashes; // Wrote "//" at the beginning of the current line.
}

private static (nint, error) Write(this ptr<commentWriter> _addr_c, slice<byte> p) {
    nint _p0 = default;
    error _p0 = default!;
    ref commentWriter c = ref _addr_c.val;

    nint n = default;
    foreach (var (i, b) in p) {
        if (!c.wroteSlashes) {
            @string s = "//";
            if (b != '\n') {
                s = "// ";
            }
            {
                var (_, err) = io.WriteString(c.W, s);

                if (err != null) {
                    return (n, error.As(err)!);
                }

            }
            c.wroteSlashes = true;
        }
        var (n0, err) = c.W.Write(p[(int)i..(int)i + 1]);
        n += n0;
        if (err != null) {
            return (n, error.As(err)!);
        }
        if (b == '\n') {
            c.wroteSlashes = false;
        }
    }    return (len(p), error.As(null!)!);
}

// An errWriter wraps a writer, recording whether a write error occurred.
private partial struct errWriter {
    public io.Writer w;
    public error err;
}

private static (nint, error) Write(this ptr<errWriter> _addr_w, slice<byte> b) {
    nint _p0 = default;
    error _p0 = default!;
    ref errWriter w = ref _addr_w.val;

    var (n, err) = w.w.Write(b);
    if (err != null) {
        w.err = err;
    }
    return (n, error.As(err)!);
}

// tmpl executes the given template text on data, writing the result to w.
private static void tmpl(io.Writer w, @string text, object data) => func((_, panic, _) => {
    var t = template.New("top");
    t.Funcs(new template.FuncMap("trim":strings.TrimSpace,"capitalize":capitalize));
    template.Must(t.Parse(text));
    ptr<errWriter> ew = addr(new errWriter(w:w));
    var err = t.Execute(ew, data);
    if (ew.err != null) { 
        // I/O error writing. Ignore write on closed pipe.
        if (strings.Contains(ew.err.Error(), "pipe")) {
            @base.SetExitStatus(1);
            @base.Exit();
        }
        @base.Fatalf("writing output: %v", ew.err);
    }
    if (err != null) {
        panic(err);
    }
});

private static @string capitalize(@string s) {
    if (s == "") {
        return s;
    }
    var (r, n) = utf8.DecodeRuneInString(s);
    return string(unicode.ToTitle(r)) + s[(int)n..];
}

public static void PrintUsage(io.Writer w, ptr<base.Command> _addr_cmd) {
    ref base.Command cmd = ref _addr_cmd.val;

    var bw = bufio.NewWriter(w);
    tmpl(bw, usageTemplate, cmd);
    bw.Flush();
}

} // end help_package
